﻿using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using ST.Data;
using ST.ModelVM.ProtocolDefine;
using ST.ModelVM.ProtocolSimHost;
using ST.Simulator.Tasks;

namespace ST.Simulator.Trans
{
    public   class TCPTrans:AbstractTrans
    {
        public ILogger<TCPTrans> _logger;
        public TCPTrans(ILogger<TCPTrans> _logger)
        {
            this._logger = _logger;
        }
        public override void Start(ProtocolSim sim)
        {
            protocolSim = sim;
            StartListen();
            base.Start(sim);    
        }
        
        public override void Stop()
        {
            try
            {
                if (listenSocket != null)
                {
                    listenSocket.Close();
                    listenSocket = null;
                }
                for(var i = clients.Count - 1; i >= 0; i--)
                {
                    try {
                        clients[i].Close();
                    }
                    catch { }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Stop error");
            }

            base.Stop();    
        }
 
        Socket listenSocket;
        List<Socket> clients = new List<Socket>();
        byte[] buffer = new byte[1024];
        public void StartListen()
        {
            try
            {
                listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.Bind(new IPEndPoint(IPAddress.Any, protocolSim.Port));

                listenSocket.Listen(1000);
                listenSocket.BeginAccept(new AsyncCallback(AcceptCallback), listenSocket);
            }
            catch (Exception ex)
            {
                //GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                throw  ;
            }
        }

        private void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);

                clients.Add(handler);
                handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), handler);
                // 继续接受新的连接
                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AcceptCallback error");
            }
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            Socket handler = (Socket)ar.AsyncState;
            try
            {
              
                int bytesRead = handler.EndReceive(ar);

                if (bytesRead > 0)
                {
                    // 读取数据
                 
                    byte[] receivedData = new byte[bytesRead];
                    Array.Copy(buffer, receivedData, bytesRead);
                    if(IsModbusTcp(receivedData))
                    {
                        var trd=new TcpReqData(receivedData);
                        var mhost = TransTask.Instance.lData.Where(a => a.ProtocolSimId == protocolSim.Id).FirstOrDefault();
                        if (trd.unitId == mhost.HostId)
                        {
                            if (trd.functionCode == 5 || trd.functionCode == 6 || trd.functionCode == 10)
                            {
                                handler.Send(receivedData);
                                TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", receivedData,
                                   $"应答指令 {trd.functionCode}");
                                handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), handler);
                                //写入指令，原因返回
                                return;
                            }
                            var StartAddress = trd.StartAddress;
                            var EndAddress = trd.StartAddress + trd.ReqNum;
                            var cmd=mhost.GDSJ.Where(a=>a.Gnm==trd.functionCode
                            &&a.StartAddress<= StartAddress
                            && a.EndAddress>= EndAddress
                            ).FirstOrDefault();
                            if (cmd != null)
                            {
                                HandeGd(handler, cmd, trd, mhost, receivedData);
                                handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), handler);
                                return;
                            }
                            var cmd2 = mhost.XHSJ.Where(a => a.Gnm == trd.functionCode
                           && a.StartAddress <= StartAddress
                           && a.EndAddress >= EndAddress
                           ).FirstOrDefault();
                            if (cmd2!=null  )
                            {
                                HandeXh(handler, cmd2, trd, mhost, receivedData);
                                handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), handler);
                                return;
                            }
                        }
                        TransTask.Instance.AddSimLog(protocolSim, 0, "接收", receivedData, "无效数据");
                    }
                    else
                    {
                        TransTask.Instance.AddSimLog(protocolSim, 0, "接收", receivedData, "无效数据");
                    }
                    
 

                    // 处理数据（例如：解析协议、响应客户端等）
                    // 这里可以添加具体的业务逻辑

                    // 继续接收数据
                    handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), handler);
                }
                else
                {
                    // 客户端断开连接
                    handler.Shutdown(SocketShutdown.Both);
                    handler.Close();
                    clients.Remove(handler);
                }
            }
            catch (Exception ex)
            {
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
                _logger.LogError(ex, "ReceiveCallback error");
            }
        }

        private bool IsModbusTcp(byte[] data)
        {
            // Modbus TCP协议最小长度为7字节
            if (data.Length < 7) return false;

            // 事务标识符（通常为0）
            // 协议标识符（Modbus TCP固定为0）
            // 长度字段（包括单元标识符和功能码）
            // 单元标识符（通常为1）
            return true;
        }
        void HandeGd(Socket handler, ProtocolGDSJVM cmd,TcpReqData trd, ProtocolSimHostVM mhost, byte[] receivedData)
        {
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "接收", receivedData,
                                    $"请求 {trd.StartAddress} 个数{trd.ReqNum}");
            var StartAddress = trd.StartAddress;
            var EndAddress = trd.StartAddress + trd.ReqNum;

            byte[] senddata = null;
            if (cmd.BitData)
            {

            }
            else
            {
                var index = (StartAddress - cmd.StartAddress) * 2;
                var len = trd.ReqNum * 2;
                senddata = new byte[len];
                Array.Copy(cmd.Bytes, index, senddata, 0, len);
            }
            var sendData2 = new byte[senddata.Length + 9];
            sendData2[0] = receivedData[0];
            sendData2[1] = receivedData[1];
            sendData2[2] = receivedData[2];
            sendData2[3] = receivedData[3];
            sendData2[4] = Convert.ToByte((senddata.Length + 3) / 256);
            sendData2[5] = Convert.ToByte((senddata.Length + 3) % 256);
            sendData2[6] = receivedData[6];
            sendData2[7] = receivedData[7];

            sendData2[8] = Convert.ToByte(senddata.Length);

            Array.Copy(senddata, 0, sendData2, 9, senddata.Length);

            var sendnum=handler.Send(sendData2);
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", sendData2,
               $"应答 {trd.StartAddress} 有效数据{senddata.Length} 字节：{sendnum}");
        }


        void HandeXh(Socket handler, ProtocolXHSJVM cmd, TcpReqData trd, ProtocolSimHostVM mhost, byte[] receivedData)
        {
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "接收", receivedData,
                                    $"请求 {trd.StartAddress}个数 {trd.ReqNum}");
            var StartAddress = trd.StartAddress;
            var EndAddress = trd.StartAddress + trd.ReqNum;

            byte[] senddata = null;
            if (cmd.BitData)
            {

            }
            else
            {
                var index = (StartAddress - cmd.StartAddress) * 2;
                var len = trd.ReqNum * 2;
                senddata = new byte[len];
                Array.Copy(cmd.Bytes, index, senddata, 0, len);
            }
            var sendData2 = new byte[senddata.Length + 9];
            sendData2[0] = receivedData[0];
            sendData2[1] = receivedData[1];
            sendData2[2] = receivedData[2];
            sendData2[3] = receivedData[3];
            sendData2[4] = Convert.ToByte((senddata.Length + 3) / 256);
            sendData2[5] = Convert.ToByte((senddata.Length + 3) % 256);
            sendData2[6] = receivedData[6];
            sendData2[7] = receivedData[7];

            sendData2[8] = Convert.ToByte(senddata.Length);

            Array.Copy(senddata, 0, sendData2, 9, senddata.Length);

            var sendnum = handler.Send(sendData2);
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", sendData2,
                $"应答 {trd.StartAddress} 有效数据{senddata.Length} 字节：{sendnum}");

             
        }

    }
}
